
/* GCSx
** TREEVIEW.H
**
** Treeview window, for browsing worlds, libraries, etc.
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#ifndef __GCSx_TREEVIEW_H_
#define __GCSx_TREEVIEW_H_

// Treeview window

class TreeView : public Window {
protected:
    int open;

    // We use 'parent' for TreeView above us, if there is one
    // But this will be true
    int parentIsTree;
    
    // (or our frame window, so check type of parent)
    FrameWindow* myFrame;
    class WidgetScroll* myScroll;
    
    // Set to hide our top-most item; typically used on top level if appropriate
    int hideItem;

    // Starts with a top-most item
    std::string item;
    std::string sort; // item in lowercase, for sorting
    int itemWidth;
    int isCaseSensitive;
    int iconClosed;
    int iconOpen;
    
    // Can contain a list of items below it (which can be empty)
    int subitems;
    int expanded;
    int currentSelection; // -1 means no selection, 0 means us, 1+ means a subitem (cascades)
    std::vector<TreeView*> subtree;

    // ...and/or an action (function) to perform for events
    // Should expect LV_* commands or any standard command from a menu
    // Won't get dblclicks if has subitems
    // if check is true, we're just checking if command is supported return CommandSupport
    // otherwise return value is true/false whether command was used
    void* ptr;
    int code;
    int (*action)(void* ptr, int code, int command, int check);
    
    // Size and positioning of icons for each item (0 = +/-, 1 = graphical)
    static int iconX[2];
    static int iconY[2];
    static int iconWidth[2];
    static int iconHeight[2];
    static int iconIndent[2];
    
    // Size of a single item
    static int itemHeight;
    static int itemYOffset;
    
    // Icons
    static const std::string wtButtonDown;
    static const std::string wtButtonRight;
    static const std::string resourceError;
    static long int iconsLoaded;
    static SDL_Surface* iconSurface;

    enum {
        // Size of treeview icons (not the +/- kind)
        GUI_TREEVIEW_ICON_WIDTH = 16,
        GUI_TREEVIEW_ICON_HEIGHT = 16,
        
        // L/R padding for both icons
        GUI_TREEVIEW_ICON_PADDING = 2,

        // These only apply when used as a widget!
        // This is the number of X characters to fit in a standard width
        GUI_TREEVIEW_DEFAULTWIDTH = 30,
        
        // Default number of lines to show
        GUI_TREEVIEW_DEFAULTLINES = 20,
    };

    // Child items alert their parent when they expand/contract/add/remove items/rename
public:
    void childResized(int fromW, int fromH, int toW, int toH, Window* child);
protected:
    void childRenamed(TreeView* child);
    // Refreshes positions of all children without dirty anything (if we need to scrollToView)
    void positionChildren(int rescroll);

    // Selects first matching subitem of ours, recursively, as expanded
    // Returns true if found
    int selectFind(int letter);

    // Selects last subitem of ours, recursively, as expanded
    void selectLast();

    // A subitem is telling us they are selected
    void selectChild(TreeView* child);

    // We are now unselected, including any subitems
    // Always called by parent, only propogates downward
    void unselectMe();
    
    // Find position of child (0-based)
    int findChild(const TreeView* child) const;

    // Propogates upward through parents to upper frame window
    void scrollToView(int sX, int sY, int sWidth, int sHeight);

public:
    // Set hidden for top level item ONLY- if on anything else, it impacts keyboard support
    // Case sensitive affects sorting and find() by string
    TreeView(const std::string& name, void* tPtr = NULL, int tCode = 0, int (*tAction)(void* ptr, int code, int command, int check) = NULL, int hideTop = 0, int caseSensitive = 0);
    virtual ~TreeView();
    
    // If you change name, it will reorder itself within it's parent
    void changeName(const std::string& name);
    void setIcon(int tIconClosed, int tIconOpen = -1);
    int getItemHeight() const { return itemHeight; }

    int event(int hasFocus, const SDL_Event* event);
    void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset);
    WindowType windowType() const;
    void resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp);
    CommandSupport supportsCommand(int cmdCode) const;
    
    // By default, treeviews do NOT want to be deleted, they are static views you can
    // close then reopen later as-is
    int wantsToBeDeleted() const;

    // Insert an item "under" us; owns pointer; sorts automatically
    void insert(TreeView* toInsert, int makeCurrent = 1);
    
    // Find a node (subnode only- won't find self)
    TreeView* find(void* fPtr);
    TreeView* findRecursive(void* fPtr);
    TreeView* find(const std::string& fItem);
    TreeView* findRecursive(int fCode, int (*fAction)(void* ptr, int code, int command, int check) = NULL);
    TreeView* findParent();
    TreeView* findSelected();
    
    int getCode() const { return code; }
    
    // Find and remove an item (and DELETE it, normally)
    void remove(TreeView* toRemove, int deleteIt = 1);
    void removeAll(); // Deletes all
    
    // Do we have subitems? Expand or collapse
    // Derived versions can create their subtrees on the fly
    virtual int hasSubItems() const; // Only checked if subtree is NOT expanded
    virtual void expand(int state = 1);
    
    // Select this item
    void selectMe();
    // Select first subitem but only if expanded
    void selectFirst();

    // Creates a FrameWindow, adds self to desktop
    void runWindowed();
    
    // Adds self to dialog using a WScroll
    void addTo(class Dialog* dialog, int showWidth = -1, int showLines = -1, int cId = 0);

    // Are we open?
    int isOpen() const { return open; }
};

#endif

